package com.example.gaoyang.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.gaoyang.constant.Constant;
import com.example.gaoyang.domain.PileLonLat;
import com.example.gaoyang.domain.request.PileLonLatRequest;
import com.example.gaoyang.domain.vo.PileLonLatVO;
import com.example.gaoyang.exception.InvalidParameterException;
import com.example.gaoyang.mapper.PileLonLatMapper;
import com.example.gaoyang.service.PileLonLatService;
import com.example.gaoyang.util.PileUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

@Slf4j
@Service
@Transactional
public class PileLonLatServiceImpl extends ServiceImpl<PileLonLatMapper, PileLonLat> implements PileLonLatService {

    @Override
    public void addPileLonLat(PileLonLatRequest request) {
        PileLonLat pileLonLat = BeanUtil.copyProperties(request, PileLonLat.class);
        this.save(pileLonLat);
    }

    @Override
    public List<PileLonLatVO> getPileLonLatList(PileLonLatRequest request) {
        LambdaQueryWrapper<PileLonLat> wrapper = getQueryWrapper(request);
        return BeanUtil.copyToList(this.list(wrapper), PileLonLatVO.class);
    }

    @Override
    public void updatePileLonLat(PileLonLatRequest request) {
        String id = request.getId();
        if (StringUtils.isEmpty(id)) {
            throw new InvalidParameterException("参数id不为空");
        }
        PileLonLat pileLonLat = BeanUtil.copyProperties(request, PileLonLat.class);
        this.updateById(pileLonLat);
    }

    @Override
    public void deletePileLonLat(PileLonLatRequest request) {
        String id = request.getId();
        if (StringUtils.isEmpty(id)) {
            throw new InvalidParameterException("参数id不为空");
        }
        this.removeById(id);
    }

    @Override
    public PileLonLatVO getClosestPileLonLat(PileLonLatRequest request) {
        // 道路编码不为空
        String roadCode = request.getRoadNo();
        if (StringUtils.isEmpty(roadCode)) {
            throw new InvalidParameterException("参数道路编码不为空");
        }
        // 如果道路编码有下划线,就取下划线之前的
        if (roadCode.contains(Constant.UNDERLINE)) {
            roadCode = roadCode.substring(0, roadCode.indexOf(Constant.UNDERLINE));
        }
        // 桩号是否满足格式
        String mileage = request.getMileage();
        if (!PileUtil.isValidPileCode(mileage)) {
            return new PileLonLatVO();
        }
        // 该桩号的桩号数值
        Long mileageNum = PileUtil.parsePileCodeToNumber(mileage);
        // 按道路编码进行筛选，并按mileage转换为数字后升序排序
        List<PileLonLat> pileLonLats = this.list(new LambdaQueryWrapper<PileLonLat>()
                .eq(PileLonLat::getRoadNo, roadCode)
        );
        // 在内存中按桩号数值升序排序
        pileLonLats.sort((p1, p2) -> {
            Long num1 = PileUtil.parsePileCodeToNumber(p1.getMileage());
            Long num2 = PileUtil.parsePileCodeToNumber(p2.getMileage());
            if (num1 == null && num2 == null) return 0;
            if (num1 == null) return 1;
            if (num2 == null) return -1;
            return num1.compareTo(num2);
        });
        // 在pileLonLats中寻找与mileage差距最小的
        int minDiff = Integer.MAX_VALUE;
        // 最接近的百度桩号
        PileLonLat closestPileLonLat = new PileLonLat();
        for (PileLonLat pileLonLat : pileLonLats) {
            // 桩号转换为数字
            Long pileLonLatNum = PileUtil.parsePileCodeToNumber(pileLonLat.getMileage());
            if (pileLonLatNum == null) {
                continue;
            }
            int diff = Math.abs(mileageNum.intValue() - pileLonLatNum.intValue());
            if (diff < minDiff) {
                minDiff = diff;
                closestPileLonLat = pileLonLat;
            }
        }
        return BeanUtil.copyProperties(closestPileLonLat, PileLonLatVO.class);
    }

    private LambdaQueryWrapper<PileLonLat> getQueryWrapper(PileLonLatRequest request) {
        return new LambdaQueryWrapper<PileLonLat>()
                .eq(StringUtils.isNotEmpty(request.getId()), PileLonLat::getId, request.getId())
                .like(StringUtils.isNotEmpty(request.getMileage()), PileLonLat::getMileage, request.getMileage())
                .eq(StringUtils.isNotEmpty(request.getRoadNo()), PileLonLat::getRoadNo, request.getRoadNo())
                .like(StringUtils.isNotEmpty(request.getRoadName()), PileLonLat::getRoadName, request.getRoadName())
                .eq(StringUtils.isNotEmpty(request.getCode()), PileLonLat::getCode, request.getCode());
    }
}
